package cn.wolfcode.service.impl;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.domain.AccountLog;
import cn.wolfcode.domain.AccountTransaction;
import cn.wolfcode.domain.OperateIntergralVo;
import cn.wolfcode.mapper.AccountLogMapper;
import cn.wolfcode.mapper.AccountTransactionMapper;
import cn.wolfcode.mapper.UsableIntegralMapper;
import cn.wolfcode.service.IUsableIntegralService;
import cn.wolfcode.web.msg.IntergralCodeMsg;
import com.alibaba.fastjson.JSON;
import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;


@Service
public class UsableIntegralServiceImpl implements IUsableIntegralService {
    @Autowired
    private UsableIntegralMapper usableIntegralMapper;
    @Autowired
    private AccountTransactionMapper accountTransactionMapper;
    @Autowired
    private AccountLogMapper accountLogMapper;

    //减积分
    @Transactional
    public void decrIntergral(OperateIntergralVo operateIntergralVo) {
        //1、插入减积分的流水记录：利用mysql主键，避免多次减积分
        AccountLog accountLog = new AccountLog();
        accountLog.setPkValue(operateIntergralVo.getPk());
        accountLog.setAmount(operateIntergralVo.getValue());
        accountLog.setType(AccountLog.TYPE_DECR);
        accountLog.setGmtTime(new Date());
        accountLog.setInfo(operateIntergralVo.getInfo());
        accountLogMapper.insert(accountLog);
        //2、操作数据库减积分(给当前用户):参数为当前用户id以及要减的积分数量
        usableIntegralMapper.decrIntegral(operateIntergralVo.getUserId(),operateIntergralVo.getValue());
    }

    @Transactional
    public void incrInrergral(OperateIntergralVo operateIntergralVo) {
        //1、插入加积分的流水记录表
        AccountLog accountLog = new AccountLog();
        accountLog.setPkValue(operateIntergralVo.getPk());
        accountLog.setAmount(operateIntergralVo.getValue());
        accountLog.setType(AccountLog.TYPE_INCR);
        accountLog.setGmtTime(new Date());
        accountLog.setInfo(operateIntergralVo.getInfo());
        accountLogMapper.insert(accountLog);
        //2、操作数据库加积分
        usableIntegralMapper.addIntergral(operateIntergralVo.getUserId(),operateIntergralVo.getValue());
    }
    //为了检查第二阶段的事务是否需要执行；一般需要提前操作数据库，对某些状态做检查.
    @Override
    public void initTry(BusinessActionContext context, OperateIntergralVo operateIntergralVo) throws InterruptedException {
        System.err.println("进入try方法..");
//        Thread.sleep(10000);
        //当执行了try方法，需要插入事务执行的痕迹
        common_insert_transaction_Log(context,operateIntergralVo,
                AccountTransaction.INCR_STATE_INTERGRAL,AccountTransaction.STATE_TRY);
//        Thread.sleep(10000);

    }
    //为加积分业务逻辑，提供事务保证；
    @Override
    public void incrIntergralConfirm(BusinessActionContext context) {
        System.err.println("进入confirm方法..");
        Object operateIntergralVo = context.getActionContext("operateIntergralVo");
        OperateIntergralVo operateIntergralVo1 = JSON.parseObject(operateIntergralVo.toString(), OperateIntergralVo.class);
        System.out.println(operateIntergralVo);
        //**为了解决confirm幂等性问题(除了单独使用AccountLog流水表，类似的我们也能使用一张事务日志表)
        AccountTransaction accountTransaction = accountTransactionMapper.get(context.getXid(), String.valueOf(context.getBranchId()));
        if (accountTransaction==null){//如果事务日志记录为空，则插入一条记录（状态为已提交）
            common_insert_transaction_Log(context,operateIntergralVo1,AccountTransaction.INCR_STATE_INTERGRAL,AccountTransaction.STATE_COMMIT);
        }
        if(AccountTransaction.STATE_TRY==accountTransaction.getState()){//如果记录是初始化，则正常逻辑操作
            //正常执行业务逻辑（属于分支事务）
            //1、加积分
            usableIntegralMapper.addIntergral(operateIntergralVo1.getUserId(),operateIntergralVo1.getValue());
        }else if(AccountTransaction.STATE_COMMIT==accountTransaction.getState()){//如果已提交了，解决幂等性问题
            //处理confirm幂等性问题
        }else {
            System.out.println("执行confirm抛异常");
        }

    }
    //根据try（）的结果，是否回滚;做回补操作
    @Override
    public void incrIntergralRollback(BusinessActionContext context) {
        Object operateIntergralVo = context.getActionContext("operateIntergralVo");
        OperateIntergralVo operateIntergralVo1 = JSON.parseObject(operateIntergralVo.toString(), OperateIntergralVo.class);
        System.err.println("进入rollback方法..");
        //(根据全局事务xid和分支事务id)查出事务日志记录
        AccountTransaction accountTransaction = accountTransactionMapper.get(context.getXid(), String.valueOf(context.getBranchId()));
        if (accountTransaction==null){//如果为空，插入事务日志记录
            common_insert_transaction_Log(context,operateIntergralVo1,
                    AccountTransaction.INCR_STATE_INTERGRAL,AccountTransaction.STATE_CANCEL);
        }
        if(AccountTransaction.STATE_TRY==accountTransaction.getState()){//如果try已经执行了，则可以进行回滚
            //修改事务记录状态为回滚状态
            accountTransactionMapper.updateAccountTransactionState(context.getXid(),String.valueOf(context.getBranchId()),
                    AccountTransaction.STATE_CANCEL,AccountTransaction.STATE_TRY);
        }else if (AccountTransaction.STATE_CANCEL==accountTransaction.getState()){//如果已经为回滚状态，则处理幂等问题
            //处理幂等问题（这里不做）
        }else {//状态都不满足
            System.out.println("执行rollbck抛异常");
        }

    }

    private void common_insert_transaction_Log(BusinessActionContext context,
                                               OperateIntergralVo operateIntergralVo,String type,Integer status){
        AccountTransaction accountTransaction = new AccountTransaction();
        accountTransaction.setTxId(context.getXid());
        accountTransaction.setActionId(String.valueOf(context.getBranchId()));
        accountTransaction.setAmount(operateIntergralVo.getValue());
        accountTransaction.setGmtCreated(new Date());
        accountTransaction.setGmtModified(new Date());
        accountTransaction.setUserId(operateIntergralVo.getUserId());
        accountTransaction.setType(type);
        accountTransaction.setState(status);
        accountTransactionMapper.insert(accountTransaction);
    }

}
